package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strconv"
)

func main() {

	// getFileInfo()

	//createFile()

	//readFile()

	//writeFile()

	//source := "/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile01.txt"
	//dest := "/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile03.txt"
	//copyFile01(source, dest, 1024)
	//copyFile02(source, dest)

	// 传输源文件地址
	//srcFile := "/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile01.txt"
	// 传输的目标位置
	//destFile := "/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile04.txt"
	// 临时记录文件
	//tempFile := "/Users/zhanghang/GolandProjects/goLearning/code/test_file/temp.txt"
	//reusableDownload(srcFile, destFile, tempFile)

	//bufioTest()

	filepath := "/Users/zhanghang/GolandProjects"
	listDirAndFile(filepath, 0)
}

// 遍历文件夹
func listDirAndFile(filepath string, tableint int) {
	tab := "|--"
	for range tableint {
		tab = "|  " + tab
	}

	dir := filepath
	fileinfos, _ := os.ReadDir(dir)
	for _, file := range fileinfos {
		filename := dir + "/" + file.Name()
		fmt.Printf("%s%s\n", tab, filename)

		if file.IsDir() {
			listDirAndFile(filename, tableint+1)
		}

	}
}

// bufio提高文件读写效率
func bufioTest() {
	// 读取文件
	//file, err := os.Open("/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile01.txt")
	//if err != nil {
	//	log.Println(err)
	//}
	//defer file.Close()
	// 创建一个bufio包下的 reader对象。
	//bufioReader := bufio.NewReader(file)
	//buf := make([]byte, 1024)
	//n, err := bufioReader.Read(buf)
	//fmt.Println("读取到了多少个字节：", n)

	// 写文件
	file, _ := os.OpenFile("/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile05.txt",
		os.O_RDWR|os.O_CREATE,
		os.ModePerm)
	defer file.Close()
	// bufio
	fileWrite := bufio.NewWriter(file)
	writeNum, _ := fileWrite.WriteString("salisalisali")
	fmt.Println("writeNum:", writeNum)
	// 发现并没有写出到文件，是留在了缓冲区，所以我们需要调用 flush 刷新缓冲区
	// 手动刷新进文件
	fileWrite.Flush()
}

// 断点续传
func reusableDownload(srcFile, destFile, tempFile string) {
	// 创建对应的file对象，连接起来
	file1, _ := os.Open(srcFile)
	file2, _ := os.OpenFile(destFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
	file3, _ := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
	defer file1.Close()
	defer file2.Close()
	defer file3.Close()
	fmt.Println("file1/2/3 文件连接建立完毕")

	// 1、读取temp.txt
	file3.Seek(0, io.SeekStart)
	buf := make([]byte, 1024, 1024)
	n, _ := file3.Read(buf)
	// 2、转换成string - 数字。
	countStr := string(buf[:n])
	count, _ := strconv.ParseInt(countStr, 10, 64)
	fmt.Println("temp.txt中记录的值为：", count) // 5120

	// 3、设置读写的偏移量
	file1.Seek(count, io.SeekStart)
	file2.Seek(count, io.SeekStart)
	fmt.Println("file1/2 光标已经移动到了目标位置")

	// 4、开始读写（复制、上传）
	bufData := make([]byte, 1024, 1024)
	// 5、需要记录读取了多少个字节
	total := int(count)

	for {
		// 读取数据
		readNum, err := file1.Read(bufData)
		if err == io.EOF { // file1 读取完毕了
			fmt.Println("文件传输完毕了")
			file3.Close()
			os.Remove(tempFile)
			break
		}

		// 向目标文件中写入数据
		writeNum, err := file2.Write(bufData[:readNum])

		// 将写入数据放到 total中, 在这里total 就是传输的进度
		total = total + writeNum
		// temp.txt 存放临时记录数据
		file3.Seek(0, io.SeekStart) // 将光标重置到开头
		file3.WriteString(strconv.Itoa(total))

	}
}

func copyFile02(source, destination string) {
	// 读取文件
	sourceFile, err := os.Open(source)
	if err != nil {
		fmt.Println("Open错误:", err)
	}
	// 输出文件 O_WRONLY , O_CREATE 如果不不存在，则会创建
	destinationFile, err := os.OpenFile(destination, os.O_WRONLY|os.O_CREATE, os.ModePerm)
	if err != nil {
		fmt.Println("OpenFile错误:", err)
	}
	// 关闭
	defer sourceFile.Close()
	defer destinationFile.Close()

	// 具体的实现
	written, err := io.Copy(destinationFile, sourceFile)
	fmt.Println("文件的字节大小:", written)
}

func copyFile01(source, destination string, bufferSize int) {
	// 读取文件
	sourceFile, err := os.Open(source)
	if err != nil {
		fmt.Println("Open错误:", err)
	}
	// 输出文件 O_WRONLY , O_CREATE 如果不不存在，则会创建
	destinationFile, err := os.OpenFile(destination, os.O_WRONLY|os.O_CREATE, os.ModePerm)
	if err != nil {
		fmt.Println("OpenFile错误:", err)
	}
	// 关闭
	defer sourceFile.Close()
	defer destinationFile.Close()

	// 专注业务代码，拷贝
	buf := make([]byte, bufferSize)
	// 读取
	for {
		n, err := sourceFile.Read(buf)
		if n == 0 || err == io.EOF {
			fmt.Println("读取完毕源文件,复制完毕")
			break
		} else if err != nil {
			fmt.Println("读取错误:", err)
			return // 错误之后，必须要return终止函数执行。
		}
		// 将缓冲区的东西写出到目标文件
		_, err = destinationFile.Write(buf[:n])
		if err != nil {
			fmt.Println("写出错误：", err)
		}
	}
}

func writeFile() {
	// os_O_WRONLY可写 | os.O_RDONLY可读 | os.O_APPEND追加  的模式写文件
	file, err := os.OpenFile("/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile01.txt", os.O_RDONLY|os.O_WRONLY|os.O_APPEND, os.ModePerm)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	bs := []byte{65, 66, 67, 68, 69}
	n, err := file.Write(bs)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(n)

	// 字符串输入
	n, err = file.WriteString("hello, sali")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(n)
}

func readFile() {
	file, err := os.Open("/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile01.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(file.Name())
	defer file.Close()

	bs := make([]byte, 1024, 1024)
	n, err2 := file.Read(bs)
	fmt.Println(n)
	fmt.Println(string(bs))
	fmt.Println(err2)
}

func createFile() {
	// 创建文件夹
	err := os.Mkdir("/Users/zhanghang/Desktop/gotest", os.ModePerm)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("文件夹创建完毕")

	// 创建层级文件夹
	err2 := os.MkdirAll("/Users/zhanghang/Desktop/gotest2/gotest201", os.ModePerm)
	if err2 != nil {
		fmt.Println(err2)
	}
	fmt.Println("层级文件夹创建完毕")

	// 移除文件夹
	err3 := os.RemoveAll("/Users/zhanghang/Desktop/gotest")
	if err3 != nil {
		fmt.Println(err3)
	}
	fmt.Println("层级文件夹删除完毕")

	file, err4 := os.Create("/Users/zhanghang/Desktop/gotestfile.txt")
	fmt.Println(file.Name())
	fmt.Println(err4)
	fmt.Println("文件创建完毕")
	os.Remove("/Users/zhanghang/Desktop/gotestfile.txt")
	fmt.Println("文件删除完毕")
}

func getFileInfo() {
	fileinfo, err := os.Stat("/Users/zhanghang/GolandProjects/goLearning/code/test_file/testFile01.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(fileinfo.Name())
	fmt.Println(fileinfo.IsDir())
	fmt.Println(fileinfo.Size())
	fmt.Println(fileinfo.ModTime())
	fmt.Println(fileinfo.Mode())

	fmt.Println(fileinfo.Sys())
}
